﻿using Menu.Exceptions;
using MenuService.Interfaces;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace MenuService.Loaders
{
    internal class TxtFileMenuLoader : IMenuProvider
    {
        private String _configPath;

        private class MenuReadBufferItem
        {
            public String CommandText { get; set; }
            public String CommandKey  { get; set; }
            public String ParentKey   { get; set; }

            public override bool Equals(object obj)
            {
                MenuReadBufferItem b = obj as MenuReadBufferItem;
                if (b == null)
                    return false;

                return     this.CommandText == b.CommandText && 
                           this.CommandKey  == b.CommandKey && 
                           this.ParentKey   ==  b.ParentKey;
            }

            public override int GetHashCode()
            {
                unchecked
                {
                    return this.CommandText.GetHashCode() + this.CommandKey.GetHashCode() + this.ParentKey.GetHashCode();
                }
            }
        }

        private class MenuReadBufferItemComparer : IComparer<MenuReadBufferItem>
        {
            public int Compare(MenuReadBufferItem x, MenuReadBufferItem y)
            {
                int key1Number =  x.CommandKey.Split('.').Length - 1;
                int key2Number =  y.CommandKey.Split('.').Length - 1;

                return key1Number - key2Number;
            }
        }

        public TxtFileMenuLoader(String path)
        {
            _configPath = path;
        }

        private List<MenuReadBufferItem> LoadFromFile()
        {
            List<MenuReadBufferItem> buffer = new List<MenuReadBufferItem>();

            using (StreamReader reader = File.OpenText(_configPath))
            {
                String line;

                while ((line = reader.ReadLine()) != null)
                {
                    int firstSpacePos = line.IndexOf(' ');
                    if (firstSpacePos < 0)
                        throw new MenuServiceException(MenuLogicFaults.BadConfigFile);

                    String commandText = line.Substring(firstSpacePos + 1);
                    String commandKey = line.Substring(0, firstSpacePos);

                    int lastDotPos = commandKey.LastIndexOf('.');
                    String parentKey = lastDotPos > 0 ? commandKey.Substring(0, lastDotPos) : null;

                    buffer.Add(new MenuReadBufferItem() { CommandKey = commandKey, CommandText = commandText, ParentKey = parentKey });
                }
            }
            buffer.Sort(new MenuReadBufferItemComparer());

            return buffer;
        }

        private MenuItem FindItem (IEnumerable<MenuItem> itemsStorage ,String commandKey)
        {
            MenuItem result = null;

            foreach (MenuItem mi in itemsStorage)
            {
                if (mi.ItemKey == commandKey)
                    return mi;

                if (mi.ChildItems != null)
                    result = FindItem(mi.ChildItems, commandKey);

                if (result != null)
                    break;
            }

            return result;
        }

        public Menu LoadMenu()
        {
            Menu mResult = new Menu();

            List<MenuReadBufferItem> buffer = LoadFromFile();

            Dictionary<string, MenuItem> processedItems = new Dictionary<string, MenuItem>();

            foreach (MenuReadBufferItem bufferItem in buffer)
            {
                if (bufferItem.ParentKey == null)
                {
                    //root item
                    MenuItem newItem = new MenuItem(bufferItem.CommandKey, bufferItem.CommandText);
                    mResult.AddRootItem(newItem);
                    processedItems.Add(bufferItem.CommandKey, newItem);
                }
                else
                {
                    //nested item
                    //TODO: Implement full tree scan for proper parent node lookup 
                    MenuItem existingItem = FindItem(processedItems.Values, bufferItem.ParentKey);// processedItems[bufferItem.ParentKey];

                    existingItem.AddChild(bufferItem.CommandText,bufferItem.CommandKey);
                }
            }
            return mResult;
        }
    }
}
